package scatter.common.rest.advise;

import com.baomidou.mybatisplus.core.metadata.IPage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.http.server.ServletServerHttpResponse;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import scatter.common.pojo.vo.BaseVo;
import scatter.common.rest.controller.SuperController;
import scatter.common.rest.tools.ErrorLogCollectorTool;
import scatter.common.rest.tools.InterfaceTool;
import scatter.common.rest.trans.TransHelper;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.AnnotatedElement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 全局响应格式封装
 * 注意：使用@RestController注解或@ResponseBody注解才能被拦截到
 * Created by yangwei
 * Created at 2019/7/26 19:42
 */
@RestControllerAdvice
@Slf4j
public class GlobalResponseBodyAdvice implements ResponseBodyAdvice, InterfaceTool {


    @Autowired
    private TransHelper transHelper;


    /**
     * 哪些类或注解处理
     */
    private static final Class[] SUPPORTS = {
            SuperController.class,
            BaseVo.class,
            IPage.class,
            List.class
    };

    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        AnnotatedElement element = returnType.getAnnotatedElement();
        Class containingClass = returnType.getContainingClass();

        List<Class> classes = new ArrayList<>();
        classes.addAll(Arrays.stream(SUPPORTS).collect(Collectors.toList()));
        return classes.stream().anyMatch(anno ->
                anno.isAnnotation() && (element.isAnnotationPresent(anno) || containingClass !=null && containingClass.isAnnotationPresent(anno) )
                        || anno.isAssignableFrom(containingClass)

        );
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        // 设置允许跨域
        fillCorsHeader(request, response);
        if (body != null) {
            body = transHelper.trans(body);

        }
        ErrorLogCollectorTool.collect("responseBody",body);
        // 正常数据不再包装
        return body;
    }

    /**
     * 添加允许跨域请求头
     * @param serverHttpRequest
     * @param serverHttpResponse
     */
    private void fillCorsHeader(ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse){
        ServletServerHttpRequest serverRequest = (ServletServerHttpRequest)serverHttpRequest;
        ServletServerHttpResponse serverResponse = (ServletServerHttpResponse)serverHttpResponse;
        if(serverRequest == null || serverResponse == null
                || serverRequest.getServletRequest() == null || serverResponse.getServletResponse() == null) {

        }

        // 对于未添加跨域消息头的响应进行处理
        HttpServletRequest request = serverRequest.getServletRequest();
        HttpServletResponse response = serverResponse.getServletResponse();
        String originHeader = "Access-Control-Allow-Origin";
        if(!response.containsHeader(originHeader)) {
            String origin = request.getHeader("Origin");
            if(origin == null) {
                String referer = request.getHeader("Referer");
                if(referer != null){
                    origin = referer.substring(0, referer.indexOf("/", 7));
                }

            }
            if (origin != null) {
                response.setHeader("Access-Control-Allow-Origin", origin);
            }
        }

        String allowHeaders = "Access-Control-Allow-Headers";
        if (!response.containsHeader(allowHeaders)) {
            String allowHeadersValue =  request.getHeader(allowHeaders);
            if (!isStrEmpty(allowHeadersValue)) {
                response.setHeader(allowHeaders, request.getHeader(allowHeaders));
            }
        }

        String allowMethods = "Access-Control-Allow-Methods";
        if (!response.containsHeader(allowMethods)) {
            response.setHeader(allowMethods, "GET,POST,OPTIONS,HEAD");
        }
        //这个很关键，要不然ajax调用时浏览器默认不会把这个token的头属性返给JS
        String exposeHeaders = "access-control-expose-headers";
        if (!response.containsHeader(exposeHeaders)) {
            response.setHeader(exposeHeaders, "x-auth-token");
        }
    }
}
